#include "Usuario.h"
#include "CajaChat.h"
//#include "ReceptorChat.h"
// Macro para que no haya problemas con el formato UINT64
#ifdef __cplusplus
#define __STDC_CONSTANT_MACROS
#ifdef _STDINT_H
#undef _STDINT_H
#endif
#include <stdint.h>
#endif
// Las librerias de ffmpeg son escritas en lenguaje C
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libswscale/swscale.h>
}
#include <cstdio>
#include <gtkmm-2.4/gtkmm/main.h>
#include <glibmm-2.4/glibmm/refptr.h>
#include <gdkmm-2.4/gdkmm/window.h>
#include <gdkmm-2.4/gdkmm/drawable.h>
#include <gdkmm-2.4/gdkmm/pixbuf.h>
#include "CodificadorVideo.h"
#include <fstream>
#include <iostream>
#include <sstream>
using std::endl;
using std::cerr;
using std::cout;
using std::string;

Usuario::Usuario(char* ip_serv, char* puerto, char* puerto_av) {
	this->nombre_usuario = "";
	this->clave = "";

	this->serv_addr.sin_family = AF_INET;
	inet_aton(ip_serv, &(this->serv_addr.sin_addr));
	this->serv_addr.sin_port = htons(atoi(puerto));
	memset(&(this->serv_addr.sin_zero), '\0', 8);

	this->serv_addr_av.sin_family = AF_INET;
	inet_aton(ip_serv, &(this->serv_addr_av.sin_addr));
	this->serv_addr_av.sin_port = htons(atoi(puerto_av));
	memset(&(this->serv_addr_av.sin_zero), '\0', 8);
	conectado = false;
	logeado = false;
	//receptor_chat = NULL;
	cajaChat = new CajaChat(this);
}

// instr_o_alumn = '0' si es instructor, '1' si es alumno
int Usuario::login(string nom_usuario, string clave, char instr_o_alumn) {
	this->nombre_usuario = nom_usuario;
	this->clave = clave;
	if((nom_usuario.size() <= 0) && (clave.size() <= 0)) {
		cerr << "Campos vacios" << endl;
		return -2;
	}
	if(!conectado) {
		this->socket = new Socket();
		this->socket_av = new Socket();
		if (!this->socket->conectar(&this->serv_addr)) {
			cerr << "No se conecto al 1" << endl;
			return -3;
		}
		if (!this->socket_av->conectar(&this->serv_addr_av)) {
			cerr << "No se conecto al 2" << endl;
			return -3;
		}
		conectado = true;
	}
	char cod_op = instr_o_alumn;
	int tam_arg = this->nombre_usuario.size() + this->clave.size() + 2;
	std::string aux = nombre_usuario + clave;
	if (!this->socket->enviar(&cod_op, sizeof(cod_op))) {
		std::cerr << "no se pudo enviar" << std::endl;
		return -3;
	}
	if (!this->socket->enviar(&tam_arg, sizeof(tam_arg))) {
		std::cerr << "no se pudo enviar" << std::endl;
		return -3;
	}
	if (!this->socket->enviar(nombre_usuario.c_str(), nombre_usuario.size() + 1)) {
		std::cerr << "no se pudo enviar" << std::endl;
		return -3;
	}
	if (!this->socket->enviar(clave.c_str(), clave.size() + 1)) {
		std::cerr << "no se pudo enviar" << std::endl;
		return -3;
	}
	// Recibo confirmacion de login
	char codRespuesta;
	if(this->recibirRespuesta(&codRespuesta) == -1) {
    	std::cerr << "No se pudo recibir la respuesta de crear clase" << std::endl;
    	return -3;
	}
	if(codRespuesta == '0') {
		cerr << "Usuario/Clave erronea" << endl;
		return -4;
	}
	if(codRespuesta == '1') {
	  this->crear_hilos_de_recepcion();
	  logeado = true;
	}
	return 0;
}

int Usuario::logout() {
	socket->shutDown();
	delete socket;
	socket_av->shutDown();
	delete socket_av;
	return 0;
}

void Usuario::desconectar() {
	conectado = false;
	logeado = false;
}

CajaChat* Usuario::getCajaChat() {
  return this->cajaChat;
}

int Usuario::enviar_texto_chat_al_servidor(string &texto) {
  // Pregunta si esta en clase y luego envia el texto al servidor
  if (this->esta_en_clase()) {
    char cod_op = 'F';
    int tam_arg = texto.size() + 1;
    if (!this->socket->enviar(&cod_op, sizeof(cod_op))) {
      std::cerr << "No se pudo enviar" << std::endl;
      return -1;
    }
    if (!this->socket->enviar(&tam_arg, sizeof(tam_arg))) {
      std::cerr << "No se pudo enviar" << std::endl;
      return -1;
    }
    if (!this->socket->enviar(texto.c_str(), texto.size() + 1)) {
      std::cerr << "No se pudo enviar" << std::endl;
      return -1;
    }
  }
  return 0;
}
void Usuario::enviar_texto_chat_al_chat(std::string &texto) {
  this->cajaChat->recibir_texto(texto);
}


int Usuario::recibirRespuesta(char *cod1) {
	if(!socket->recibir(cod1, 1)) {
		std::cerr << "No se pudo recibir el codigo1" << std::endl;
		return -1;
	}
	return 0;
}

int Usuario::enviarDatos(char cod_op, int tam_arg, std::string datos) {
	if (!socket->enviar(&cod_op, sizeof(cod_op))) {
		std::cerr << "No se pudo enviar" << std::endl;
		return -1;
	}
	if (!socket->enviar(&tam_arg, sizeof(tam_arg))) {
		std::cerr << "No se pudo enviar" << std::endl;
		return -1;
	}

	if (!socket->enviar(datos.c_str(), datos.size() + 1)) {
		std::cerr << "No se pudo enviar" << std::endl;
		return -1;
	}
	return 0;
}

unsigned int Usuario::String_toInt(std::string str) {
	unsigned int entero = 0;
	std::stringstream ss;
	ss << str;
	ss >> entero;
	return entero;
}

std::string Usuario::Int_toString(unsigned int entero) {
	std::string str;
	std::stringstream ss;
	ss << entero;
	ss >> str;
	return str;
}

Usuario::~Usuario() {
	if (conectado) {
		this->socket->shutDown();
		this->socket_av->shutDown();
		delete this->socket;
		delete this->socket_av;
	}
/*	if (receptor_chat != NULL) {
	  receptor_chat->join();
	  delete this->receptor_chat;
	}*/
}
